package guyubao.com.controller;

import guyubao.com.entity.RestBean;
import guyubao.com.entity.Users;
import guyubao.com.entity.vo.request.*;
import guyubao.com.entity.vo.response.AuthorizeVo;
import guyubao.com.service.AccountService;
import guyubao.com.service.RedisService;
import guyubao.com.utils.Const;
import guyubao.com.utils.JwtUtils;
import guyubao.com.utils.SendMailType;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import javax.validation.constraints.Email;

import org.hibernate.validator.constraints.Length;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.Calendar;
import java.util.Date;

@Validated
@RestController
@RequestMapping("/api/auth")
@Tag(name = "登录校验相关", description = "包括用户登录、注册、验证码请求等操作。")
public class AuthorizeController extends BaseController{
    @Resource
    AccountService service;
    @Resource
    RedisService redisService;
    @Resource
    JwtUtils utils;
    @Resource
    SendMailType sendMailType;
    @Value("${spring.security.jwt.expire}")
    private int expire;
    
    @Operation(summary ="退出登录")
    @GetMapping("/logout")
    public RestBean<String> logout(HttpServletRequest request){
        String authorization = request.getHeader("Authorization");
        if (utils.deleteJwt(authorization)) {
            return RestBean.success("退出登录成功！");
        } else {
            return RestBean.failure(400, "退出登录失败！");
        }
    }
    @Operation(summary ="请求邮件验证码")
    @GetMapping("/ask-code")
    public RestBean<Void> askVerifyCode(@Parameter(description = "目标邮箱",example = "123@126.com")
                                            @RequestParam @Email String email,
                                        @Parameter(description = "类型 ",example = "register|resetPassword|resetUserName|resetEmail|login|apply|message|relieveJDAccount|relieveAccount|updateJDCertificate|updateJDAccountComment")
                                        @RequestParam  String type,
                                        HttpServletRequest request){
        if (!sendMailType.isExistence(type)) {
            return RestBean.failure(400,"请输入正确的参数");
        }
        return this.messageHandle(()->
                service.sendEmailVerifyCode(type,email,request.getRemoteAddr()));
    }
    @Operation(summary ="根据用户名获得邮箱地址")
    @GetMapping("/ask-code-username")
    public RestBean<Void> askVerifyCodeUsername(@Parameter(description = "用户",example = "xx")
                                        @RequestParam @Length(min = 1,max = 100) String username,
                                        @Parameter(description = "类型 ",example = "register|resetPassword|resetUserName|resetEmail|login|apply|message|relieveJDAccount|relieveAccount|updateJDCertificate|updateJDAccountComment")
                                        @RequestParam  String type,
                                        HttpServletRequest request){
        if (!sendMailType.isExistence(type)) {
            return RestBean.failure(400,"请输入正确的参数");
        }
        return this.messageHandle(()->
                service.sendEmailVerifyCodeOther(type,"username",username,request.getRemoteAddr()));
    }
    @Operation(summary ="用户注册操作")
    @PostMapping("/register")
    public RestBean<Void> register(@Parameter(description = "json提供用户名、邮箱、密码、验证码",
            example = "{'email':'w2799604016@163.com','username':'w2799604016@163.com','password':'123456','code':'123456'}")
                                       @RequestBody @Valid EmailRegisterVoRequest vo){
        return this.messageHandle(vo,service::registerEmailAccount);
    }
    @Operation(summary ="密码修改：邮箱确认")
    @PutMapping("/reset-confirm")
    public RestBean<Void> resetConfirm(@RequestBody @Valid ConfirmResetVoRequest vo){
        return this.messageHandle(vo,service::resetConfirm);
    }
    @Operation(summary ="密码修改：修改密码")
    @PutMapping("/reset-password")
    public RestBean<Void> resetConfirm(@RequestBody @Valid EmailResetVoRequest vo){
        return this.messageHandle(vo,service::resetEmailAccountPassword);
    }
    @Operation(summary ="修改用户名")
    @PutMapping("/reset-username")
    public RestBean<Void> resetUsername(@RequestBody @Valid ResetUsernameVoRequest vo,
                                        @RequestAttribute String id,
                                        @RequestAttribute String email){
        if (service.findAccountByNameOrEmail(vo.getUsername())!=null)
            return RestBean.failure("用户名已存在,请提交新的用户名");
        //  内部重复验证
        String resetUserName = resetVerify(vo.getId(),vo.getCode(), id,email, "resetUserName");
        if (resetUserName!=null) return RestBean.failure(resetUserName);
        // 执行业务
        return this.messageHandle(vo,service::resetUserName);
    }
    @Operation(summary ="修改邮箱")
    @PutMapping("/reset-email")
    public RestBean<Void> resetEmail(@RequestBody @Valid ResetEmailVoRequest vo,
                                        @RequestAttribute String id,
                                     @RequestAttribute String email){
        if (service.findAccountByNameOrEmail(vo.getEmail())!=null)
            return RestBean.failure("邮箱已存在,请提交新的邮箱");
        //  内部重复验证
        String resetUserName = resetVerify(vo.getId(), vo.getCode(), id,email, "resetEmail");
        if (resetUserName!=null) return RestBean.failure(resetUserName);
        // 执行业务
        return this.messageHandle(vo,service::resetEmail);
    }
    //  重复验证
    private String resetVerify(String voId, String voCode, String id, String email,String type){
        if (!voId.equals(id)) return "凭证不一致!";
        if (id==null) return "需要登录才能修改用户名";
        // 获得邮箱
        if (email==null) return "未能获取您的邮箱,请联系管理人员！";
        // 获取验证码并校验
        return redisService.verificationCode(voCode,type,email);
    }
    @Operation(summary ="删除用户")
    @DeleteMapping("/delete")
    public RestBean<Void> deleteAccount(@RequestParam @Length(max = 6,min = 6) String code,
                                     @RequestAttribute String id,
                                     @RequestAttribute String email){
        //  内部重复验证
        if (id==null||email==null||id.isEmpty()||email.isEmpty())return RestBean.failure("需要有凭证才能删除");
        String verification = redisService.verificationCode(code, "relieveAccount", email);
        if (verification!=null) return RestBean.failure(verification);
        // 执行删除用户
        String s = service.deleteOneself(id);
        // 删除redis在线用户凭证
        if (s==null)redisService.delKey(Const.JWT_WHITE_LIST + id);
        return this.messageHandle(()-> s);
    }
    @Operation(summary ="续签")
    @GetMapping("/renew")
    public RestBean<AuthorizeVo> renewAccount(Authentication authentication,@RequestAttribute String id){
        //  内部重复验证
        if (id==null||id.isEmpty())return RestBean.failure("需要有凭证才能删除");
        // 获得自己编辑Users类是继承User
        Users user = (Users) authentication.getPrincipal();
        // 获取过期时间
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.SECOND, 3600 * 24 * expire);
        Date time = calendar.getTime();
        // 创建token
        String token = utils.createJwt(user, user.getId(), user.getName(),user.getEmail(),user.getRole());
        // 创建显示信息
        AuthorizeVo vo = user.asViewObject(AuthorizeVo.class, v -> {
            v.setRole(user.getRole());
            v.setToken(token);
            v.setExpire(time);
        });
        return RestBean.success(vo);
    }
}
